#pragma once

#include <iostream>
#include <queue>
#include <vector>
#include <functional>
#include "log.hpp"
#include "Pthread.hpp"
#include "LockGuard.hpp"
using namespace std;
int defaultnum = 5;
class TThreadData
{
public:
    TThreadData(const std::string &name) : threadname(name)
    {
    }
    ~TThreadData()
    {
    }
    std::string threadname;
};
template <class T>
class Threadpool
{
private:
    Threadpool(int thread_num = defaultnum) : _thread_num(thread_num)
    {
        pthread_mutex_init(&__mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
        for (int i = 0; i < _thread_num; i++)
        {
            string threadname = "thread ";
            threadname += to_string(i + 1);
            TThreadData td(threadname);
            _threads.emplace_back(threadname, bind(&Threadpool<T>::ThreadRun, this, std::placeholders::_1), td);
            lg.massage(Info, "%s is created...\n", threadname.c_str());
        }
    }
    Threadpool(const Threadpool<T> &tp) = delete;
    const Threadpool<T> &operator=(const Threadpool<T> &tp) = delete;

public:
    static Threadpool<T> *GetInstance()
    {
        if (instance == nullptr)
        {
            LockGuard lockguard(&sig_lock);
            if (instance == nullptr)
            {
                lg.massage(Info, "创建单例成功...\n");
                instance = new Threadpool<T>();
            }
        }
        return instance;
    }
    void start()
    {
        for (auto &_thread : _threads)
        {
            _thread.Start();
            lg.massage(Info, "%s is running ...\n", _thread._threadname.c_str());
        }
        // return true;
    }
    void ThreadWait(const TThreadData &td)
    {
        lg.massage(Debug, "no task, %s is sleeping...\n", td.threadname.c_str());
        pthread_cond_wait(&_cond, &__mutex);
    }
    void ThreadWakeup()
    {
        pthread_cond_signal(&_cond);
    }
    void ThreadRun(TThreadData &td)
    {
        // cout<<"线程is running"<<endl;
        // lg.massage(Info, "%s is running ...\n", td.threadname.c_str());
        while (true)
        {
            T t;
            {
                LockGuard lockguard(&__mutex);
                while (_q.empty())
                {
                    ThreadWait(td);
                    lg.massage(Debug, "thread %s is wakeup\n", td.threadname.c_str());
                }
                t = _q.front();
                _q.pop();
            }
            t();
        }
    }
    void push(T &in)
    {
        LockGuard lockguard(&__mutex);
        _q.push(in);
        ThreadWakeup();
    }
    void Wait()
    {
        for (auto &thread : _threads)
        {
            thread.Join();
        }
    }
    ~Threadpool()
    {
        pthread_mutex_destroy(&__mutex);
        pthread_cond_destroy(&_cond);
    }

private:
    std::queue<T> _q;
    std::vector<Thread<TThreadData>> _threads;
    int _thread_num;
    pthread_mutex_t __mutex;
    pthread_cond_t _cond;

    static Threadpool<T> *instance;
    static pthread_mutex_t sig_lock;
};
template <class T>
Threadpool<T> *Threadpool<T>::instance = nullptr;
template <class T>
pthread_mutex_t Threadpool<T>::sig_lock = PTHREAD_MUTEX_INITIALIZER;